﻿namespace Microsoft.VisualStudio.ServiceModel.DomainServices.Tools
{
    using Microsoft.Win32;
    using System;
    using System.CodeDom;
    using System.Collections.Generic;
    using System.Data.Linq;
    using System.Data.Linq.Mapping;
    using System.IO;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Linq;

    internal class LinqToSqlContext : BusinessLogicContext
    {
        private System.Data.Linq.DataContext _dataContext;
        private System.Data.Linq.Mapping.MetaModel _metaModel;
        private const string AssemblyPathKeyValueName = "AssemblyPath";
        private const string EnableDataContextKeyValueName = "EnableDataContext";
        private static string linqToSqlDomainServiceAssemblyPath;
        private const string ToolkitDomainServiceWizardRegKey = @"SOFTWARE\Microsoft\WCFRIAServices\v1.0\Toolkit\DomainServiceWizard";
        private static bool EnableDataContextTypes_TestOverride_k__BackingField;

        public LinqToSqlContext(Type contextType) : base(contextType, contextType.Name)
        {
        }

        protected override CodeTypeDeclaration CreateBusinessLogicClass(CodeGenContext codeGenContext, CodeNamespace codeNamespace, string className)
        {
            if (linqToSqlDomainServiceAssemblyPath == null)
            {
                return null;
            }
            foreach (string str in BusinessLogicClassConstants.LinqToSqlImports)
            {
                codeNamespace.Imports.Add(new CodeNamespaceImport(str));
            }
            if (base.ContextType.Namespace != codeNamespace.Name)
            {
                codeNamespace.Imports.Add(new CodeNamespaceImport(base.ContextType.Namespace));
            }
            codeGenContext.AddReference(typeof(System.Data.Linq.DataContext).Assembly.FullName);
            codeGenContext.AddReference(linqToSqlDomainServiceAssemblyPath);
            CodeTypeDeclaration declaration = CodeGenUtilities.CreateTypeDeclaration(className, codeNamespace.Name);
            CodeTypeReference reference = new CodeTypeReference(BusinessLogicClassConstants.LinqToSqlDomainServiceTypeName, new CodeTypeReference[] { new CodeTypeReference(base.ContextType.Name) });
            declaration.BaseTypes.Add(reference);
            return declaration;
        }

        protected override IEnumerable<BusinessLogicEntity> CreateEntities()
        {
            IEnumerable<MetaTable> enumerable = from t in this.MetaModel.GetTables()
                where t.RowType.IsEntity
                select t;
            List<BusinessLogicEntity> list = new List<BusinessLogicEntity>();
            foreach (MetaTable table in enumerable)
            {
                MetaType rowType = table.RowType;
                list.Add(new LinqToSqlEntity(this, rowType));
            }
            return list;
        }

        protected override void GenerateDeleteMethod(CodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, BusinessLogicEntity entity)
        {
            string name = CodeGenUtilities.MakeLegalParameterName(entity.Name);
            CodeMemberMethod method = new CodeMemberMethod();
            businessLogicClass.Members.Add(method);
            LinqToSqlEntity entity2 = (LinqToSqlEntity) entity;
            method.Name = "Delete" + CodeGenUtilities.MakeLegalEntityName(entity.Name);
            method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            method.Parameters.Add(new CodeParameterDeclarationExpression(entity.ClrType.Name, name));
            CodeExpression targetObject = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "DataContext");
            CodeExpression expression2 = new CodePropertyReferenceExpression(targetObject, entity2.TablePropertyName);
            CodeMethodInvokeExpression expression3 = new CodeMethodInvokeExpression(expression2, "Attach", new CodeExpression[] { new CodeArgumentReferenceExpression(name) });
            method.Statements.Add(expression3);
            CodeMethodInvokeExpression expression4 = new CodeMethodInvokeExpression(expression2, "DeleteOnSubmit", new CodeExpression[] { new CodeArgumentReferenceExpression(name) });
            method.Statements.Add(expression4);
        }

        protected override void GenerateInsertMethod(CodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, BusinessLogicEntity entity)
        {
            CodeMemberMethod method = new CodeMemberMethod();
            businessLogicClass.Members.Add(method);
            string name = CodeGenUtilities.MakeLegalParameterName(entity.Name);
            LinqToSqlEntity entity2 = (LinqToSqlEntity) entity;
            method.Name = "Insert" + CodeGenUtilities.MakeLegalEntityName(entity.Name);
            method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            method.Parameters.Add(new CodeParameterDeclarationExpression(entity.ClrType.Name, name));
            CodeExpression targetObject = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "DataContext");
            CodeExpression expression2 = new CodePropertyReferenceExpression(targetObject, entity2.TablePropertyName);
            CodeMethodInvokeExpression expression3 = new CodeMethodInvokeExpression(expression2, "InsertOnSubmit", new CodeExpression[] { new CodeArgumentReferenceExpression(name) });
            method.Statements.Add(expression3);
        }

        protected override CodeMemberMethod GenerateSelectMethod(CodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, BusinessLogicEntity entity)
        {
            CodeMemberMethod method = null;
            LinqToSqlEntity entity2 = entity as LinqToSqlEntity;
            if ((entity2 != null) && (entity2.TablePropertyName != null))
            {
                method = new CodeMemberMethod();
                businessLogicClass.Members.Add(method);
                method.Comments.Add(new CodeCommentStatement(Resources.BusinessLogicClass_Query_Method_Remarks, false));
                method.Name = "Get" + CodeGenUtilities.MakeLegalEntityName(entity2.TablePropertyName);
                method.ReturnType = new CodeTypeReference("IQueryable", new CodeTypeReference[] { new CodeTypeReference(entity.Name) });
                method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                CodeExpression targetObject = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "DataContext");
                CodeExpression expression = new CodePropertyReferenceExpression(targetObject, entity2.TablePropertyName);
                CodeMethodReturnStatement statement = new CodeMethodReturnStatement(expression);
                method.Statements.Add(statement);
            }
            return method;
        }

        protected override void GenerateUpdateMethod(CodeGenContext codeGenContext, CodeTypeDeclaration businessLogicClass, BusinessLogicEntity entity)
        {
            string name = "current" + entity.ClrType.Name;
            CodeMemberMethod method = new CodeMemberMethod();
            businessLogicClass.Members.Add(method);
            LinqToSqlEntity entity2 = (LinqToSqlEntity) entity;
            method.Name = "Update" + CodeGenUtilities.MakeLegalEntityName(entity.Name);
            method.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            method.Parameters.Add(new CodeParameterDeclarationExpression(entity.ClrType.Name, name));
            if (!entity2.HasTimestampMember)
            {
                CodeExpression targetObject = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "ChangeSet");
                CodeMethodReferenceExpression expression2 = new CodeMethodReferenceExpression(targetObject, "GetOriginal");
                CodeMethodInvokeExpression expression3 = new CodeMethodInvokeExpression(expression2, new CodeExpression[] { new CodeArgumentReferenceExpression(name) });
                CodeExpression expression4 = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "DataContext");
                CodeExpression expression5 = new CodePropertyReferenceExpression(expression4, entity2.TablePropertyName);
                CodeMethodInvokeExpression expression6 = new CodeMethodInvokeExpression(expression5, "Attach", new CodeExpression[] { new CodeArgumentReferenceExpression(name), expression3 });
                method.Statements.Add(expression6);
            }
            else
            {
                CodeExpression expression7 = new CodePropertyReferenceExpression(new CodeThisReferenceExpression(), "DataContext");
                CodeExpression expression8 = new CodePropertyReferenceExpression(expression7, entity2.TablePropertyName);
                CodeMethodInvokeExpression expression9 = new CodeMethodInvokeExpression(expression8, "Attach", new CodeExpression[] { new CodeArgumentReferenceExpression(name), new CodePrimitiveExpression(true) });
                method.Statements.Add(expression9);
            }
        }

        internal static void OverrideAssemblyPath(string assemblyPath)
        {
            EnableDataContextTypes_TestOverride = !string.IsNullOrEmpty(assemblyPath);
            linqToSqlDomainServiceAssemblyPath = assemblyPath;
        }

        public override string DataAccessLayerName
        {
            get
            {
                return Resources.BusinessLogicClass_LinqToSql;
            }
        }

        private System.Data.Linq.DataContext DataContext
        {
            get
            {
                if (this._dataContext == null)
                {
                    try
                    {
                        this._dataContext = (System.Data.Linq.DataContext) Activator.CreateInstance(base.ContextType, new object[] { string.Empty });
                    }
                    catch (TargetInvocationException exception)
                    {
                        if (exception.InnerException != null)
                        {
                            throw exception.InnerException;
                        }
                        throw;
                    }
                }
                return this._dataContext;
            }
        }

        public static bool EnableDataContextTypes
        {
            get
            {
                if (EnableDataContextTypes_TestOverride)
                {
                    return true;
                }
                linqToSqlDomainServiceAssemblyPath = null;
                RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\WCFRIAServices\v1.0\Toolkit\DomainServiceWizard");
                if (key != null)
                {
                    object obj2 = key.GetValue("EnableDataContext", string.Empty);
                    int result = 0;
                    if (((obj2 != null) && int.TryParse(obj2.ToString(), out result)) && (result == 1))
                    {
                        string path = key.GetValue("AssemblyPath", null) as string;
                        if (File.Exists(path))
                        {
                            try
                            {
                                Assembly.LoadFrom(path);
                                linqToSqlDomainServiceAssemblyPath = path;
                            }
                            catch (FileNotFoundException)
                            {
                            }
                            catch (BadImageFormatException)
                            {
                            }
                            catch (FileLoadException)
                            {
                            }
                        }
                    }
                    key.Close();
                }
                return (linqToSqlDomainServiceAssemblyPath != null);
            }
        }

        private static bool EnableDataContextTypes_TestOverride
        {
            [CompilerGenerated]
            get
            {
                return EnableDataContextTypes_TestOverride_k__BackingField;
            }
            [CompilerGenerated]
            set
            {
                EnableDataContextTypes_TestOverride_k__BackingField = value;
            }
        }

        internal static string LinqToSqlDomainServiceAssemblyPath
        {
            get
            {
                if (!EnableDataContextTypes)
                {
                    return null;
                }
                return linqToSqlDomainServiceAssemblyPath;
            }
        }

        private System.Data.Linq.Mapping.MetaModel MetaModel
        {
            get
            {
                if (this._metaModel == null)
                {
                    this._metaModel = this.DataContext.Mapping;
                }
                return this._metaModel;
            }
        }
    }
}

